const Page = require('./model').Page
const callFunction = require('../../util/callFunction')
const ObjectID = require('mongodb').ObjectID
const webpack = require('webpack')
const merge = require('webpack-merge')
const path = require('path')
const fs = require('fs')
var webpackConfig = require(path.join(process.cwd(), 'build', 'webpack.base.conf.js'))
var config = require(path.join(process.cwd(), 'config'))
var utils = require(path.join(process.cwd(), 'build', 'utils'))
const ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var CopyWebpackPlugin = require('copy-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ejs = require('ejs')
const _ = require('lodash')

function detailPage (id, _cb, _err) {
  var db = global.db.collection(Page.prototype.dbName)
  db.findOne({ _id: ObjectID(id) }, function (err, b) {
    if (err) {
      callFunction(_err, err)
      return
    }
    callFunction(_cb, b)
  })
}

function listPage (_cb, _err) {
  var db = global.db.collection(Page.prototype.dbName)
  var pages = db.find().toArray(function (err, b) {
    if (err) {
      callFunction(_err, err)
      return
    }
    callFunction(_cb, b)
  })
  return pages
}

function addPage (pages, _cb, _err) {
  var db = global.db.collection(Page.prototype.dbName)
  if (!Array.isArray(pages)) pages = [pages]
  db.insertMany(pages, function (err, b) {
    if (err) {
      callFunction(_err, err)
      return
    }
    callFunction(_cb, b)
  })
}

function changePageContent (id, page, _cb, _err) {
  var db = global.db.collection(Page.prototype.dbName)
  db.findOneAndUpdate({ _id: ObjectID(id) },
    { $set: page },
    function (err, b) {
      if (err) {
        callFunction(_err, err)
        return
      }
      callFunction(_cb, b)
    })
}

function softDeletePage (id, _cb, _err) {
  var db = global.db.collection(Page.prototype.dbName)
  db.findOneAndUpdate({ _id: ObjectID(id) },
    { $set: { _delete: 1 } },
    function (err, b) {
      if (err) {
        callFunction(_err, err)
        return
      }
      callFunction(_cb, b)
    })
}

function genaratePage (pageId, _cb, _err) {
  global.db.collection('version').findOne({ actived: true }, function (err, b) {
    if (err) {
      callFunction(_err, err)
      console.error(err)
      return
    }
    var styles = []
    var scripts = []

    _getFiles(path.join(process.cwd(), 'dist', 'v' + b.version), styles, scripts, path.join(process.cwd(), 'dist'))
    global.db.collection(Page.prototype.dbName).findOne({_id: ObjectID(pageId)}, function (err, page) {
      if (err) {
        callFunction(_err, err)
        console.error(err)
        return
      }
      _genaratePage(styles, page.title, page, scripts, _cb, _err)
    })
  })
}

function _getFiles (p, styles, scripts, statics) {
  console.log(p, styles, scripts)
  var assets = fs.readdirSync(p)
  for (var i = 0; i < assets.length; i++) {
    var info = fs.statSync(path.join(p, assets[i]))
    if (info.isDirectory()) {
      _getFiles(path.join(p, assets[i]), styles, scripts, statics)
      continue
    }
    console.log(p, assets[i], info.isDirectory())
    if (/\.(css)(\?.*)?$/.test(assets[i])) {
      styles.push(path.join(p, assets[i]).replace(statics, ''))
    } else if (/\.(js)$/.test(assets[i])) {
      scripts.push(path.join(p, assets[i]).replace(statics, ''))
    }
  }
}

function _genaratePage (styles, title, initial, scripts, _cb, _err) {
  console.log(path.join(__dirname, '../genTemplates/index.ejs'))
  ejs.renderFile(path.join(__dirname, '../genTemplates/index.ejs'), {
    styles: styles,
    title: title,
    initial: JSON.stringify(initial),
    scripts: scripts
  }, function (err, data) {
    if (err) {
      console.error(err)
      callFunction(_err, err)
      return
    }
    console.log(data)
    fs.writeFileSync(path.join(process.cwd(), 'dist', 'index1.html'), data)
    callFunction(_cb, data)
  })
}

function genarateAssets (_cb, _err) {
  var db = global.db.collection('version')
  db.findOne({ actived: true }, function (err, b) {
    if (err || !b) {
      callFunction(_err, err)
      return
    }
    db.findOneAndUpdate({ _id: ObjectID(b._id) },
      { $set: { actived: false } },
      function (err) {
        if (err) {
          callFunction(_err, err)
          return
        }
        _webpack(b, _cb, _err)
      })
  })
}

function _webpack (v, _cb, _err) {
  process.env.NODE_ENV = 'development'
  var thisVersion = v.version + 1
  var versionPath = 'v' + thisVersion + '/'
  var assetsPath = versionPath + 'static/'
  fs.exists(assetsPath, function (exist) {
    if (exist) {
      v.version = thisVersion
      _webpack(v)
      return
    }
    var genConfig = merge(webpackConfig, {
      entry: path.join(process.cwd(), 'src', 'genMain.js'),
      output: {
        path: path.join(process.cwd(), 'dist'),
        filename: assetsPath + 'js/[name].js',
        chunkFilename: assetsPath + 'js/[id].js'
      },
      devtool: false,
      module: {
        rules: utils.styleLoaders({
          sourceMap: config.build.productionSourceMap,
          extract: true
        })
      },
      plugins: [
        new ExtractTextPlugin({
          filename: assetsPath + 'css/[name].css'
        }),
        new OptimizeCSSPlugin({
          cssProcessorOptions: {
            safe: true
          }
        }),
        new webpack.optimize.UglifyJsPlugin({
          compress: {
            warnings: false
          },
          sourceMap: true
        }),
        new webpack.optimize.CommonsChunkPlugin({
          name: 'vendor',
          minChunks: function (module, count) {
            // any required modules inside node_modules are extracted to vendor
            return (
              module.resource &&
              /\.js$/.test(module.resource) &&
              module.resource.indexOf(
                path.join(process.cwd(), 'node_modules')
              ) === 0
            )
          }
        }),
        new HtmlWebpackPlugin({
          filename: versionPath + 'index.html',
          template: 'index.html',
          inject: true,
          minify: {
            removeComments: true,
            collapseWhitespace: true,
            removeAttributeQuotes: true
            // more options:
            // https://github.com/kangax/html-minifier#options-quick-reference
          },
          // necessary to consistently work with multiple chunks via CommonsChunkPlugin
          chunksSortMode: 'dependency'
        }),
        // extract webpack runtime and module manifest to its own file in order to
        // prevent vendor hash from being updated whenever app bundle is updated
        new webpack.optimize.CommonsChunkPlugin({
          name: 'manifest',
          chunks: ['vendor']
        }),
        new CopyWebpackPlugin([
          {
            from: path.join(process.cwd(), 'static'),
            to: config.build.assetsSubDirectory,
            ignore: ['.*']
          }
        ])
      ]
    })

    _.remove(genConfig.module.rules, function (item) {
      return item.loader === 'url-loader'
    })
    genConfig = merge(genConfig, {
      module: {
        rules: [
          {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            loader: 'url-loader',
            options: {
              limit: 10000,
              name: assetsPath + 'img/[name].[ext]'
            }
          },
          {
            test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
            loader: 'url-loader',
            options: {
              limit: 10000,
              name: assetsPath + 'media/[name].[ext]'
            }
          },
          {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
            loader: 'url-loader',
            options: {
              limit: 10000,
              name: assetsPath + 'fonts/[name].[ext]'
            }
          }
        ]
      }
    })

    console.log('webpack begin to genarate assets', JSON.stringify(genConfig))
    webpack(genConfig, function (err, stats) {
      if (err) {
        console.error(err)
        return callFunction(_err, err)
      }
      global.db.collection('version').insertOne(
        {version: thisVersion,
          actived: true,
          createTime: new Date()
        }, function (err, insertB) {
        if (err) {
          console.error(err)
          return callFunction(_err, err)
        }
        console.log('webpack genarate assets success')
        callFunction(_cb)
      })
    })
  })
}

module.exports = {
  listPage: listPage,
  addPage: addPage,
  changePageContent: changePageContent,
  detailPage: detailPage,
  softDeletePage: softDeletePage,
  genaratePage: genaratePage,
  genarateAssets: genarateAssets
}
